using System;
using System.Collections.Generic;
using System.Linq;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Models.TreeDataGrid;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Shapes;
using Avalonia.Controls.Templates;
using Avalonia.Data;
using Avalonia.Input;
using Avalonia.Layout;
using Avalonia.Media;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.VisualBasic;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using ReactiveUI;
using SocketTool.Model.BindingModels;
using SocketTool.Model.Enums;

namespace SocketTool.Helper
{
    public static class TreeDataGridHelper
    {
        public static HierarchicalTreeDataGridSource<ReqParamBindingModel> CreateHierachicalColumns(
            IList<ReqParamBindingModel> list,
            string createBortherCommand,
            string createChildCommand,
            string removeCommand)
        {
            if (string.IsNullOrEmpty(createBortherCommand))
                throw new ArgumentNullException("createBortherCommand");
            if (string.IsNullOrEmpty(createChildCommand))
                throw new ArgumentNullException("createChildCommand");
            if (string.IsNullOrEmpty(removeCommand))
                throw new ArgumentNullException("removeCommand");

            var valueTypes = Enum.GetValues<SocketTool.Model.Enums.JsonValueTypeEnum>();
            var valueTypeList = valueTypes.Select(s => s.ToString()).ToList();
            //获取全局通用的字体模板
            var defaultFountResource = App.Current.Resources["GenericFont"] as FontFamily;

            //生成层级结构的Tree模板
            var expanderTemplate = new FuncDataTemplate<ReqParamBindingModel>((v, c) =>
            {
                return new ToggleButton()
                {
                    Name = "treeDataGridToggleButton",
                    [!ToggleButton.IsCheckedProperty] = new Binding("IsExpanded", BindingMode.TwoWay),
                    // [!ToggleButton.IsVisibleProperty] = new Binding("HasChild"),
                    Width = 40,
                    HorizontalAlignment = HorizontalAlignment.Center,
                    VerticalAlignment = VerticalAlignment.Center,
                    HorizontalContentAlignment = HorizontalAlignment.Center,
                    VerticalContentAlignment = VerticalAlignment.Center
                };
            });
            //生成选中框单元格模板
            var cbxTemplate = new FuncDataTemplate<ReqParamBindingModel>((v, c) =>
            {
                return new CheckBox
                {
                    [!CheckBox.IsCheckedProperty] = new Binding("IsChecked", BindingMode.TwoWay),
                    VerticalAlignment = VerticalAlignment.Center
                };
            });
            //生成Key值输入文本框模板
            var keyTbxTemplate = new FuncDataTemplate<ReqParamBindingModel>((v, c) =>
            {
                return new TextBox()
                {
                    [!TextBox.TextProperty] = new Binding("Key", BindingMode.TwoWay),
                    FontFamily = defaultFountResource,
                    Watermark = "Key",
                    Margin = new Thickness(6)
                };
            });
            //生成Value输入文本框模板
            var valueTbxTemplate = new FuncDataTemplate<ReqParamBindingModel>((v, c) =>
            {
                return new TextBox()
                {
                    [!TextBox.TextProperty] = new Binding("Value", BindingMode.TwoWay),
                    [!TextBox.IsEnabledProperty] = new Binding("CanInputValue"),
                    FontFamily = defaultFountResource,
                    Watermark = "Value",
                    Margin = new Thickness(6)
                };
            });
            //生成ValueType下拉框选择模板
            var valueTypeTbxTemplate = new FuncDataTemplate<ReqParamBindingModel>((v, c) =>
            {
                return new ComboBox()
                {
                    [!ComboBox.SelectedIndexProperty] = new Binding("ValueType", BindingMode.TwoWay),
                    Items = valueTypeList,
                    Margin = new Thickness(6),
                    VerticalAlignment = VerticalAlignment.Center
                };
            });
            //生成Explan说明文本框模板
            var explanCbxTemplate = new FuncDataTemplate<ReqParamBindingModel>((v, c) =>
            {
                return new TextBox()
                {
                    [!TextBox.TextProperty] = new Binding("Explan", BindingMode.TwoWay),
                    FontFamily = defaultFountResource,
                    Watermark = "字段说明",
                    Margin = new Thickness(6)
                };
            });
            //生成操作按钮模板
            var operationTemplate = new FuncDataTemplate<ReqParamBindingModel>((v, c) =>
            {
                StackPanel sp = new StackPanel()
                    {Orientation = Orientation.Horizontal, VerticalAlignment = VerticalAlignment.Center};
                sp.Children.Add(new Button()
                {
                    Content = new Path() {Name = "AddBortherBtnIcon", Width = 24, Height = 24},
                    Classes = new Classes("JsonParamBtn"),
                    [!Button.CommandProperty] = new Binding()
                    {
                        Path = $"DataContext.{createBortherCommand}",
                        RelativeSource = new RelativeSource()
                        {
                            Mode = RelativeSourceMode.FindAncestor,
                            AncestorType = typeof(UserControl)
                        }
                    },
                    [!Button.CommandParameterProperty] = new Binding("."),
                    Background = Brushes.Transparent,
                    HorizontalContentAlignment = HorizontalAlignment.Center,
                    VerticalContentAlignment = VerticalAlignment.Center
                });
                sp.Children.Add(new Button()
                {
                    Content = new Path() {Name = "AddChildBtnIcon", Width = 24, Height = 24},
                    Classes = new Classes("JsonParamBtn"),
                    Margin = new Thickness(6, 0),
                    [!Button.CommandProperty] = new Binding()
                    {
                        Path = $"DataContext.{createChildCommand}",
                        RelativeSource = new RelativeSource()
                        {
                            Mode = RelativeSourceMode.FindAncestor,
                            AncestorType = typeof(UserControl)
                        }
                    },
                    [!Button.CommandParameterProperty] = new Binding("."),
                    Background = Brushes.Transparent,
                    HorizontalContentAlignment = HorizontalAlignment.Center,
                    VerticalContentAlignment = VerticalAlignment.Center
                });
                sp.Children.Add(new Button()
                {
                    Content = new Path() {Classes = new Classes("RemoveBtnIcon"), Width = 24, Height = 24},
                    Classes = new Classes("JsonParamBtn"),
                    [!Button.CommandProperty] = new Binding()
                    {
                        Path = $"DataContext.{removeCommand}",
                        RelativeSource = new RelativeSource()
                        {
                            Mode = RelativeSourceMode.FindAncestor,
                            AncestorType = typeof(UserControl)
                        }
                    },
                    [!Button.CommandParameterProperty] = new Binding("."),
                    Background = Brushes.Transparent,
                    HorizontalContentAlignment = HorizontalAlignment.Center,
                    VerticalContentAlignment = VerticalAlignment.Center
                });
                return sp;
            });


            var result = new HierarchicalTreeDataGridSource<ReqParamBindingModel>(list)
            {
                Columns =
                {
                    new HierarchicalExpanderColumn<ReqParamBindingModel>(
                        new TemplateColumn<ReqParamBindingModel>(null, expanderTemplate),
                        x => x.Children,
                        x => x.HasChild,
                        x => x.IsExpanded),
                    new TemplateColumn<ReqParamBindingModel>("启用", cbxTemplate, GridLength.Auto),
                    new TemplateColumn<ReqParamBindingModel>("Key", keyTbxTemplate, GridLength.Star),
                    new TemplateColumn<ReqParamBindingModel>("Value", valueTbxTemplate, GridLength.Star),
                    new TemplateColumn<ReqParamBindingModel>("ValueType", valueTypeTbxTemplate, GridLength.Auto),
                    new TemplateColumn<ReqParamBindingModel>("说明", explanCbxTemplate, GridLength.Star),
                    new TemplateColumn<ReqParamBindingModel>("操作", operationTemplate, GridLength.Auto)
                }
            };
            return result;
        }


        /// <summary>
        /// Json格式反序列化为字符串格式
        /// </summary>
        /// <param name="list"></param>
        /// <returns></returns>
        public static JObject Json2Texts(IList<ReqParamBindingModel> list)
        {
            if (list.Count < 1)
                return null;
            JObject result = new JObject();
            foreach (var Item in list)
            {
                if (Item.ValueType == (int) Model.Enums.JsonValueTypeEnum.Object)
                {
                    result.Add(Item.Key, Json2Texts(Item.Children));
                }
                else if (Item.ValueType == (int) Model.Enums.JsonValueTypeEnum.ObjectArray)
                {
                    var array = new JArray();
                    foreach (var child in Item.Children)
                    {
                        array.Add(Json2Texts(child.Children));
                    }

                    result.Add(Item.Key, array);
                }
                else if (((Model.Enums.JsonValueTypeEnum) Item.ValueType).ToString().Contains("Array"))
                {
                    var typeEnum = (Model.Enums.JsonValueTypeEnum) Item.ValueType;
                    switch (typeEnum)
                    {
                        case JsonValueTypeEnum.BooleanArray:
                        case JsonValueTypeEnum.DecimalArray:
                        case JsonValueTypeEnum.IntArray:
                        case JsonValueTypeEnum.LongArray:
                        {
                            object[] arrValues = Item.Value.Split(',', ' ', StringSplitOptions.None);
                            result.Add(Item.Key, new JArray(arrValues));
                            break;
                        }
                        case JsonValueTypeEnum.StringArray:
                        {
                            object[] arrValues = Item.Value.Split(',', StringSplitOptions.None);
                            result.Add(Item.Key, new JArray(arrValues));
                            break;
                        }
                    }
                }
                else
                {
                    var typeEnum = (Model.Enums.JsonValueTypeEnum) Item.ValueType;
                    switch (typeEnum)
                    {
                        case JsonValueTypeEnum.Boolean:
                            result.Add(Item.Key, bool.TryParse(Item.Value, out var boolResult) && boolResult);
                            break;
                        case JsonValueTypeEnum.Decimal:
                            result.Add(Item.Key,
                                double.TryParse(Item.Value, out var doubleResult) ? doubleResult : 0.0);
                            break;
                        case JsonValueTypeEnum.Int:
                            result.Add(Item.Key, int.TryParse(Item.Value, out var intResult) ? intResult : 0);
                            break;
                        case JsonValueTypeEnum.Long:
                            result.Add(Item.Key, long.TryParse(Item.Value, out var longResult) ? longResult : 0);
                            break;
                        default:
                            if (!string.IsNullOrEmpty(Item.Key))
                                result.Add(Item.Key, Item.Value);
                            break;
                    }
                }
            }

            return result;
        }

        /// <summary>
        /// 字符串反序列化成json格式
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static IList<ReqParamBindingModel> Text2Json(string source)
        {
            try
            {
                source = source.Replace("\r\n", string.Empty);
                List<ReqParamBindingModel> result = new();
                if (!source.StartsWith("{") || !source.EndsWith("}"))
                    return result;

                var jObj = (JObject) JsonConvert.DeserializeObject(source)!;
                if (jObj.HasValues)
                {
                    getJosn(jObj, null, result);
                }

                result.RemoveAll(w => string.IsNullOrEmpty(w.Key));
                return result;
            }
            catch (Exception ex)
            {
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine($"字符串反序列化Json格式错误 Text2Json {ex.Message}");
                Console.ResetColor();
                return null;
            }
        }

        /// <summary>
        /// 同级内是否包含重复项
        /// </summary>
        /// <returns></returns>
        public static bool CheckHasRepeatKey(IList<ReqParamBindingModel> list)
        {
            bool hasRepeat = list.GroupBy((g) => g.Key).Where(w => w.Count() > 1).Count() > 0;
            if (!hasRepeat)
                return true;
            foreach (var item in list)
            {
                if (item.Children.Count > 0)
                    return CheckHasRepeatKey(item.Children);
            }

            return false;
        }

        /// <summary>
        /// 递归反序列化所有对象
        /// </summary>
        /// <param name="token"></param>
        /// <param name="parent"></param>
        /// <param name="list"></param>
        static void getJosn(JToken token, ReqParamBindingModel parent, List<ReqParamBindingModel> list)
        {
            if (token == null || !token.HasValues)
                return;
            if (token.Type == JTokenType.Object)
            {
                var obj = (JObject) token;
                foreach (var item in obj)
                {
                    if (item.Value.HasValues)
                    {
                        Console.WriteLine($"key:{item.Key}");
                        ReqParamBindingModel model = new()
                        {
                            Key = item.Key,
                            ValueType = (int) Model.Enums.JsonValueTypeEnum.Object,
                            IsChecked = true
                        };
                        if (parent != null)
                        {
                            parent.Children.Add(model);
                            parent.HasChild = true;
                        }
                        else
                            list.Add(model);

                        getJosn(item.Value, model, list);
                    }
                    else
                    {
                        var newstr = item.Value.ToString().Replace("\r\n", string.Empty);
                        ReqParamBindingModel model = new()
                        {
                            Key = item.Key,
                            Value = newstr,
                            ValueType = propertyTypeConverter(item.Value.Type),
                            IsChecked = true
                        };
                        if (parent == null)
                            list.Add(model);
                        else
                        {
                            parent.HasChild = true;
                            parent.Children.Add(model);
                        }

                        // Console.WriteLine($"key:{item.Key} value:{newstr}  valueType:{item.Value.Type}");
                    }
                }
            }
            else if (token.Type == JTokenType.Array)
            {
                var array = (JArray) token;
                foreach (var arr in array)
                {
                    if (arr.Type != JTokenType.Object && arr.Type != JTokenType.Property)
                    {
                        var newstr = array.ToString().Replace("\r\n", string.Empty);
                        parent.ValueType = propertyArrayTypeConverter(arr.Type);
                        parent.Value = newstr;
                        parent.HasChild = false;
                        parent.Children.Clear();
                        break;
                    }

                    ReqParamBindingModel model = new()
                    {
                        IsChecked = true,
                        ValueType = (int) Model.Enums.JsonValueTypeEnum.Object
                    };
                    if (parent == null)
                        list.Add(model);
                    else
                    {
                        parent.Children.Add(model);
                        parent.ValueType = (int) Model.Enums.JsonValueTypeEnum.ObjectArray;
                        parent.HasChild = true;
                    }

                    getJosn(arr, model, list);
                }
            }
        }

        /// <summary>
        /// 获取类型
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        static int propertyTypeConverter(JTokenType type)
        {
            int result = (int) Model.Enums.JsonValueTypeEnum.String;
            switch (type)
            {
                case JTokenType.Array:
                    result = (int) Model.Enums.JsonValueTypeEnum.StringArray;
                    break;
                case JTokenType.Boolean:
                    result = (int) Model.Enums.JsonValueTypeEnum.Boolean;
                    break;
                case JTokenType.Float:
                    result = (int) Model.Enums.JsonValueTypeEnum.Decimal;
                    break;
                case JTokenType.Integer:
                    result = (int) Model.Enums.JsonValueTypeEnum.Int;
                    break;
                default:
                    result = (int) Model.Enums.JsonValueTypeEnum.String;
                    break;
            }

            return result;
        }

        /// <summary>
        /// 获取数字类型
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        static int propertyArrayTypeConverter(JTokenType type)
        {
            int result = (int) Model.Enums.JsonValueTypeEnum.String;
            switch (type)
            {
                case JTokenType.Boolean:
                    result = (int) Model.Enums.JsonValueTypeEnum.BooleanArray;
                    break;
                case JTokenType.Float:
                    result = (int) Model.Enums.JsonValueTypeEnum.DecimalArray;
                    break;
                case JTokenType.Integer:
                    result = (int) Model.Enums.JsonValueTypeEnum.IntArray;
                    break;
                case JTokenType.String:
                    result = (int) Model.Enums.JsonValueTypeEnum.StringArray;
                    break;
                default:
                    result = (int) Model.Enums.JsonValueTypeEnum.StringArray;
                    break;
            }

            return result;
        }
    }
}